home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 5 / UNZIP_1 / UNZIP.C < prev    next >
Text File  |  1992-07-19  |  42KB  |  1,830 lines

  1. /* -------------------------------------------------------------------------- */
  2. /* -------------------------------------------------------------------------- */
  3.  
  4. /*
  5.  *   UnZip - A ZIP file extract utility for ZIP files and ZIP ".EXE" files
  6.  *   archived using PKZIP 1.01 or earlier. Recognizes and dearchives ╥stored╙, 
  7.  *   ╥shrunk╙, ╥reduced╙ and ╥imploded╙ files.
  8.  *
  9.  *   VERSION: UnZip 1.01 ╤ Sep 10, 1989
  10.  *
  11.  *   Translated into Lightspeed C v.3.02 and adapted for the Mac by A.P. Maika,
  12.  *   (utilizing TransSkel 2.01 and TransDisplay 2.0 written by Paul DuBois)
  13.  *
  14.  *   Dearchiving code for ╥extracting╙, ╥unshrinking╙, and ╥expanding╙ written
  15.  *   in Turbo C v. 2.0 ⌐ Samuel H. Smith (version 1.2 of 03-15-89)
  16.  *   Adapted for the Atari ST and CRC inline assembly code ⌐ Darin Wayrynen
  17.  *        
  18.  *   Dearchiving code for ╥exploding╙ derived from Turbo Pascal v. 5.0
  19.  *   source ⌐ R.P. Byrne (version 2.0 of 07-31-89)
  20.  */
  21.  
  22. /* -------------------------------------------------------------------------- */
  23. /* -------------------------------------------------------------------------- */
  24. /*
  25.  *                     Host operating system details
  26.  */
  27.  
  28. #include <stdio.h>
  29. #include <TransDisplay.h>
  30. #include <strings.h>
  31. #include <unix.h>
  32. #include <Storage.h>
  33.  
  34. #define SEEK_CUR  1     (* lseek() modes *)
  35. #define SEEK_END  2
  36. #define SEEK_SET  0
  37. #define HIGH_LOW  1
  38.  
  39. MenuHandle        mFile,mOptions,mfilter,mstrip;
  40. CursHandle        c;
  41. WindowRecord    wprogressRec;
  42. WindowPtr        wlist,wprogress;
  43. Point            bloc =    {40,40};
  44. Rect            prect;
  45.  
  46. SFReply        SFzipfd;
  47. FInfo        ffinfo;
  48.  
  49. Boolean        finishedflag;
  50. Boolean        stripLFflag=false;
  51. Boolean        wlistflag=false;
  52. Boolean        choosefileflag=false;
  53. Boolean        TEXTfilterflag=false;
  54.  
  55. char        tstring[256],tfilename[256];
  56. long        zipoffset[100],progresscount,sizeblock;
  57. int            direntries,dindex,blockcount,numblocks;
  58.  
  59. typedef struct gifinfo
  60.     {
  61.         char    gif_signature[6];
  62.         int        screen_width;
  63.         int        screen_height;
  64.         char    color_resolution;
  65.     } gifinfo;
  66.  
  67. /* -------------------------------------------------------------------------- */
  68. /* -------------------------------------------------------------------------- */
  69. /*
  70.  * dearchiving code Copyright 1989 Samuel H. Smith;  All rights reserved
  71.  *
  72.  * Do not distribute modified versions without my permission.
  73.  * Do not remove or alter this notice or any other copyright notice.
  74.  * If you use this in your own program you must distribute source code.
  75.  * Do not use any of this in a commercial product.
  76.  *
  77.  */
  78.  
  79. #define CODE_VERSION  "UnZip:  Zipfile Extract v1.2 of 03-15-89;  (C) 1989 Samuel H. Smith"
  80.  
  81. typedef unsigned char byte;    /* code assumes UNSIGNED bytes */
  82. typedef long longint;
  83. typedef unsigned word;
  84. typedef char boolean;
  85.  
  86. #define STRSIZ 256
  87.  
  88. unsigned int in_size,out_size;
  89.  
  90. /* -------------------------------------------------------------------------- */
  91. /*
  92.  *                Zipfile layout declarations
  93.  */
  94.  
  95. typedef longint signature_type;
  96.  
  97.  
  98. #define LOCAL_FILE_HEADER_SIGNATURE  0x504B0304L
  99.  
  100.  
  101. typedef struct local_file_header {
  102.     word version_needed_to_extract;
  103.     word general_purpose_bit_flag;
  104.     int compression_method;
  105.     int last_mod_file_time;
  106.     int last_mod_file_date;
  107.     longint crc32;
  108.     longint compressed_size;
  109.     longint uncompressed_size;
  110.     int filename_length;
  111.     int extra_field_length;
  112. } local_file_header;
  113.  
  114.  
  115. #define CENTRAL_FILE_HEADER_SIGNATURE  0x504B0102L
  116.  
  117.  
  118. typedef struct central_directory_file_header {
  119.     word version_made_by;
  120.     word version_needed_to_extract;
  121.     word general_purpose_bit_flag;
  122.     word compression_method;
  123.     word last_mod_file_time;
  124.     word last_mod_file_date;
  125.     longint crc32;
  126.     longint compressed_size;
  127.     longint uncompressed_size;
  128.     word filename_length;
  129.     word extra_field_length;
  130.     word file_comment_length;
  131.     word disk_number_start;
  132.     word internal_file_attributes;
  133.     longint external_file_attributes;
  134.     longint relative_offset_local_header;
  135. } central_directory_file_header;
  136.  
  137.  
  138. #define END_CENTRAL_DIR_SIGNATURE  0x504B0506L
  139.  
  140.  
  141. typedef struct end_central_dir_record {
  142.     word number_this_disk;
  143.     word number_disk_with_start_central_directory;
  144.     word total_entries_central_dir_on_this_disk;
  145.     word total_entries_central_dir;
  146.     longint size_central_directory;
  147.     longint offset_start_central_directory;
  148.     word zipfile_comment_length;
  149. } end_central_dir_record;
  150.  
  151.  
  152.  
  153. /* -------------------------------------------------------------------------- */
  154. /*
  155.  * input file variables
  156.  *
  157.  */
  158.  
  159. #define INBUFSIZ 0x2000L
  160. byte *inbuf;                        /* input file buffer - any size is legal */
  161. byte *inptr;
  162.  
  163. int incnt;
  164. unsigned bitbuf;
  165. int bits_left;
  166. boolean zipeof;
  167.  
  168. int zipfd;
  169.  
  170. local_file_header lrec;
  171.  
  172.  
  173. /* -------------------------------------------------------------------------- */
  174. /*
  175.  * output stream variables
  176.  *
  177.  */
  178.  
  179. #define OUTBUFSIZ 0x6000L
  180. byte    *outbuf;                      /* buffer for rle look-back */
  181. byte    *outptr;
  182.  
  183. long    outpos;                        /* absolute position in outfile */
  184. int        outcnt;                        /* current position in outbuf */
  185.  
  186. int        outfd;
  187. char    filename[STRSIZ];
  188. char    extra[STRSIZ];
  189.  
  190. #define DLE 144
  191.  
  192. /* -------------------------------------------------------------------------- */
  193. /*
  194.  * shrink/reduce working storage
  195.  *
  196.  */
  197.  
  198. int        factor;
  199. byte    followers[256][64];
  200. byte    Slen[256];
  201.  
  202. #define    max_bits 13
  203. #define init_bits 9
  204. #define hsize 8192
  205. #define first_ent 257
  206. #define clear 256
  207.  
  208. int        *Prefix_of;
  209. byte    *Suffix_of;
  210. byte    *Stack;
  211.  
  212. int        codesize;
  213. int        maxcode;
  214. int        free_ent;
  215. int        maxcodemax;
  216. int        offset;
  217. int        sizex;
  218.  
  219. /* -------------------------------------------------------------------------- */
  220. /* stuff needed for exploding */
  221.  
  222. #define        LITERAL_TREE_ROOT    511
  223. #define        LIT_LAST_LEAF        255
  224. #define        DISTANCE_TREE_ROOT    127
  225. #define        DIST_LAST_LEAF         63
  226. #define        LENGTH_TREE_ROOT    127
  227. #define        LEN_LAST_LEAF         63
  228.  
  229. typedef struct SF_Node
  230.     {
  231.         int        LChild;
  232.         int        RChild;
  233.     } SF_Node;
  234.  
  235. SF_Node            SF_Literal[LITERAL_TREE_ROOT + 1];
  236. SF_Node            SF_Distance[DISTANCE_TREE_ROOT + 1];;
  237. SF_Node            SF_Length[LENGTH_TREE_ROOT + 1];
  238.  
  239. typedef struct    SF_BuildRec
  240.     {
  241.         int        Len;
  242.         int        Val;
  243.         int        Code;
  244.     } SF_BuildRec;
  245.  
  246. int                NextFreeLiteral;
  247. int                NextFreeLength;
  248. int                NextFreeDistance;
  249. int                NumOfTrees;
  250. int                MinMatchLen;
  251. int                DictSize;
  252.  
  253. /* -------------------------------------------------------------------------- */
  254. void swap_bytes(wordp)
  255. word *wordp;
  256. /* convert intel style ╘short int╒ variable to host format */
  257. {
  258.     char *charp = (char *) wordp;
  259.     char temp;
  260.  
  261.     temp = charp[0];
  262.     charp[0] = charp[1];
  263.     charp[1] = temp;
  264. }
  265.  
  266. /* -------------------------------------------------------------------------- */
  267. void swap_lbytes(longp)
  268. longint *longp;
  269. /* convert intel style ╘long╒ variable to host format */
  270. {
  271.     char *charp = (char *) longp;
  272.     char temp[4];
  273.  
  274.     temp[3] = charp[0];
  275.     temp[2] = charp[1];
  276.     temp[1] = charp[2];
  277.     temp[0] = charp[3];
  278.  
  279.     charp[0] = temp[0];
  280.     charp[1] = temp[1];
  281.     charp[2] = temp[2];
  282.     charp[3] = temp[3];
  283. }
  284.  
  285.  
  286. /* -------------------------------------------------------------------------- */
  287. int FillBuffer()
  288.  /* fill input buffer if possible */
  289. {
  290.     extern local_file_header lrec;
  291.     unsigned int readsize;
  292.  
  293.     if (lrec.compressed_size <= 0 ) return (incnt = 0);
  294.  
  295.     if (lrec.compressed_size > (long) in_size) readsize = in_size;
  296.     else readsize = (int) lrec.compressed_size;
  297.     
  298.     incnt = read(zipfd, inbuf, readsize);
  299.  
  300.     lrec.compressed_size -= incnt;
  301.     inptr = inbuf;
  302.     return (incnt--);
  303. }
  304.  
  305. /* -------------------------------------------------------------------------- */
  306. int ReadByte(x)
  307. unsigned *x;
  308.  /* read a byte; return 8 if byte available, 0 if not */
  309. {    
  310.     /* counter for UpdateProgressWind    */
  311.     if(sizeblock == ++progresscount)
  312.     {
  313.         progresscount    =    0L;
  314.         UpdateProgressWind(numblocks,++blockcount);
  315.     }
  316.     
  317.     if (incnt-- == 0)
  318.         if (FillBuffer() == 0)
  319.             return 0;
  320.  
  321.     *x = *inptr++;
  322.     return 8;
  323. }
  324.  
  325.  
  326. /* -------------------------------------------------------------------------- */
  327. static unsigned mask_bits[] =
  328.         {0,     0x0001, 0x0003, 0x0007, 0x000f,
  329.                 0x001f, 0x003f, 0x007f, 0x00ff,
  330.                 0x01ff, 0x03ff, 0x07ff, 0x0fff,
  331.                 0x1fff, 0x3fff, 0x7fff, 0xffff
  332.         };
  333.  
  334. /* -------------------------------------------------------------------------- */
  335. int FillBitBuffer(bits)
  336. register int bits;
  337. {
  338.     /* get the bits that are left and read the next word */
  339.     unsigned temp;
  340.     register int result = bitbuf;
  341.     int sbits = bits_left;
  342.     bits -= bits_left;
  343.  
  344.     /* read next word of input */
  345.     bits_left = ReadByte(&bitbuf);
  346.     bits_left += ReadByte(&temp);
  347.     bitbuf |= (temp << 8);
  348.     if (bits_left == 0)
  349.         zipeof = 1;
  350.  
  351.     /* get the remaining bits */
  352.     result = result | (int) ((bitbuf & mask_bits[bits]) << sbits);
  353.     bitbuf >>= bits;
  354.     bits_left -= bits;
  355.     return result;
  356. }
  357.  
  358. /* -------------------------------------------------------------------------- */
  359. #define READBIT(nbits,zdest) { if (nbits <= bits_left) { zdest = (int)(bitbuf & mask_bits[nbits]); bitbuf >>= nbits; bits_left -= nbits; } else zdest = FillBitBuffer(nbits);}
  360. /*
  361.  * macro READBIT(nbits,zdest)
  362.  *  {
  363.  *      if (nbits <= bits_left) {
  364.  *          zdest = (int)(bitbuf & mask_bits[nbits]);
  365.  *          bitbuf >>= nbits;
  366.  *          bits_left -= nbits;
  367.  *      } else
  368.  *          zdest = FillBitBuffer(nbits);
  369.  *  }
  370.  *
  371.  */
  372.  
  373.  
  374. /* -------------------------------------------------------------------------- */
  375. #include "crc32.h"
  376.  
  377. /* -------------------------------------------------------------------------- */
  378. void FlushOutput()
  379.  /* flush contents of output buffer */
  380. {
  381.     UpdateCRC(outbuf, outcnt);
  382.     write(outfd, outbuf, outcnt);
  383.     outpos = outpos + (long) outcnt;
  384.     outcnt = 0;
  385.     outptr = outbuf;
  386. /*    Monitor("",0,"",0,"outpos",outpos);    */
  387. }
  388.  
  389. /* -------------------------------------------------------------------------- */
  390. #define OUTB(intc) { *outptr++=intc; if (++outcnt==out_size) FlushOutput(); }
  391. /*
  392.  *  macro OUTB(intc)
  393.  *  {
  394.  *      *outptr++=intc;
  395.  *      if (++outcnt==out_size)
  396.  *          FlushOutput();
  397.  *  }
  398.  *
  399.  */
  400.  
  401. /* -------------------------------------------------------------------------- */
  402. void LoadFollowers()
  403. {
  404.     register int x;
  405.     register int i;
  406.  
  407.     for (x = 255; x >= 0; x--) 
  408.     {
  409.         READBIT(6,Slen[x]);
  410.         for (i = 0; i < Slen[x]; i++)
  411.         {
  412.             READBIT(8,followers[x][i]);
  413.         }
  414.     }
  415. }
  416.  
  417. /* -------------------------------------------------------------------------- */
  418. /*
  419.  * The Reducing algorithm is actually a combination of two
  420.  * distinct algorithms.  The first algorithm compresses repeated
  421.  * byte sequences, and the second algorithm takes the compressed
  422.  * stream from the first algorithm and applies a probabilistic
  423.  * compression method.
  424.  */
  425.  
  426. int L_table[] = {0, 0x7f, 0x3f, 0x1f, 0x0f};
  427.  
  428. int D_shift[] = {0, 0x07, 0x06, 0x05, 0x04};
  429. int D_mask[]  = {0, 0x01, 0x03, 0x07, 0x0f};
  430.  
  431. int B_table[] = {8, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5,
  432.          5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
  433.          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  434.          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
  435.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  436.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  437.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  438.          7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  439.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  440.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  441.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  442.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  443.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  444.          8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  445.          8, 8, 8, 8};
  446.  
  447. /* -------------------------------------------------------------------------- */
  448. void unReduce()
  449. /* expand probablisticly reduced data */
  450. {
  451.     register int    lchar;
  452.     register int    nchar;
  453.     int                ExState;
  454.     register int    V;
  455.     register int    Len;
  456.     int                ix,i,offset;
  457.     long            op;
  458.  
  459.     factor    =    lrec.compression_method - 1;
  460.     ExState    =    0;
  461.     lchar    =    0;
  462.     LoadFollowers();
  463.         
  464.     while (((outpos + outcnt) < lrec.uncompressed_size) && (!zipeof))
  465.     {
  466.         if (Slen[lchar] == 0)    READBIT(8,nchar)      /* ; */
  467.         
  468.         else
  469.         {
  470.             READBIT(1,nchar);
  471.             if (nchar != 0)    READBIT(8,nchar)          /* ; */
  472.  
  473.             else
  474.             {
  475.                 int follower;
  476.                 int bitsneeded = B_table[Slen[lchar]];
  477.                 READBIT(bitsneeded,follower);
  478.                 nchar = followers[lchar][follower];
  479.             }
  480.         }
  481.  
  482.         /* expand the resulting byte */
  483.         switch (ExState) 
  484.         {
  485.  
  486.         case 0:
  487.             if (nchar != DLE)    OUTB(nchar)            /* ; */
  488.             
  489.             else
  490.                 ExState = 1;
  491.                 
  492.             break;
  493.  
  494.         case 1:
  495.             if (nchar != 0) 
  496.             {
  497.                 V = nchar;
  498.                 Len = V & L_table[factor];
  499.                 if (Len == L_table[factor])    ExState = 2;
  500.                 else                        ExState = 3;
  501.             }
  502.             else 
  503.             {
  504.                 OUTB(DLE);
  505.                 ExState = 0;
  506.             }
  507.             break;
  508.  
  509.         case 2: 
  510.             {
  511.                 Len += nchar;
  512.                 ExState = 3;
  513.             }
  514.             break;
  515.  
  516.         case 3: 
  517.             {
  518.                 i = Len + 3;
  519.                 offset = (((V >> D_shift[factor]) &
  520.                                           D_mask[factor]) << 8) + nchar + 1;
  521.                 op = outpos + outcnt - offset;
  522.  
  523.                 /* special case- before start of file */
  524.                 while ((op < 0L) && (i > 0)) 
  525.                 {
  526.                     OUTB(0);
  527.                     op++;
  528.                     i--;
  529.                 }
  530.  
  531.                 /* normal copy of data from output buffer */
  532.                 {
  533.                     ix = (int) (op % out_size);
  534.  
  535.                     /* do a block memory copy if possible */
  536.                        if ( ((ix    +i) < out_size) && ((outcnt+i) < out_size) )
  537.                     {
  538.                         memcpy(outptr,&outbuf[ix],i);
  539.                         outptr += i;
  540.                         outcnt += i;
  541.                     }
  542.  
  543.                     /* otherwise copy byte by byte */
  544.                     else    while (i--) 
  545.                     {
  546.                         OUTB(outbuf[ix]);
  547.                         if (++ix >= out_size)    ix = 0;
  548.                     }
  549.                 }
  550.  
  551.                 ExState = 0;
  552.             }
  553.             break;
  554.         }
  555.  
  556.         /* store character for next iteration */
  557.         lchar = nchar;
  558.     }
  559. }
  560.  
  561. /* -------------------------------------------------------------------------- */
  562. /*
  563.  * Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm
  564.  * with partial clearing.
  565.  *
  566.  */
  567.  
  568. void partial_clear()
  569. {
  570.     extern int *Prefix_of;
  571.     register int pr;
  572.     register int cd;
  573.  
  574.     /* mark all nodes as potentially unused */
  575.     for (cd = first_ent; cd < free_ent; cd++)
  576.         *(Prefix_of + cd) |= 0x8000;
  577.  
  578.     /* unmark those that are used by other nodes */
  579.     for (cd = first_ent; cd < free_ent; cd++) {
  580.         pr = *(Prefix_of + cd) & 0x7fff;    /* reference to another node? */
  581.                 if (pr >= first_ent)            /* flag node as referenced */
  582.             *(Prefix_of +pr) &= 0x7fff;
  583.     }
  584.  
  585.     /* clear the ones that are still marked */
  586.     for (cd = first_ent; cd < free_ent; cd++)
  587.         if ((*(Prefix_of + cd) & 0x8000) != 0)
  588.             *(Prefix_of + cd) = -1;
  589.  
  590.     /* find first cleared node as next free_ent */
  591.         cd = first_ent;
  592.         while ((cd < maxcodemax) && (*(Prefix_of + cd) != -1))
  593.                 cd++;
  594.         free_ent = cd;
  595. }
  596.  
  597. /* -------------------------------------------------------------------------- */
  598. void unShrink()
  599. {
  600.    #define  GetCode(dest) READBIT(codesize,dest)
  601.  
  602.     extern int *Prefix_of;
  603.     extern byte *Suffix_of;
  604.     extern local_file_header lrec;
  605.     extern byte *Stack;
  606.     register int code;
  607.     register int stackp;
  608.     int finchar;
  609.     int oldcode;
  610.     int incode;
  611.     void partial_clear();
  612.  
  613.  
  614.     /* decompress the file */
  615.     maxcodemax = 1 << max_bits;
  616.     codesize = init_bits;
  617.     maxcode = (1 << codesize) - 1;
  618.     free_ent = first_ent;
  619.     offset = 0;
  620.     sizex = 0;
  621.  
  622.     for (code = maxcodemax; code > 255; code--)
  623.         *(Prefix_of + code) = -1;
  624.  
  625.     for (code = 255; code >= 0; code--)
  626.     {
  627.         *(Prefix_of + code) = 0;
  628.         *(Suffix_of + code) = code;
  629.     }
  630.     
  631.     GetCode(oldcode);
  632.     if (zipeof) return;
  633.     finchar = oldcode;
  634.  
  635.     OUTB(finchar);
  636.  
  637.     stackp = hsize;
  638.  
  639.     while (!zipeof) 
  640.     {    
  641.         GetCode(code);
  642.         if (zipeof) return;
  643.  
  644.         while (code == clear) 
  645.         {
  646.             GetCode(code);
  647.             switch (code) 
  648.             {
  649.  
  650.             case 1:
  651.                 {
  652.                     codesize++;
  653.                     if (codesize == max_bits)
  654.                             maxcode = maxcodemax;
  655.                     else
  656.                             maxcode = (1 << codesize) - 1;
  657.                 }
  658.                 break;
  659.  
  660.             case 2:
  661.                 partial_clear();
  662.                 break;
  663.                 
  664.             }
  665.  
  666.             GetCode(code);
  667.             if (zipeof) return;
  668.         }
  669.  
  670.  
  671.         /* special case for KwKwK string */
  672.         incode = code;
  673.         if (*(Prefix_of + code) == -1)
  674.         {
  675.             *(Stack + --stackp) = finchar;
  676.             code = oldcode;
  677.         }
  678.  
  679.  
  680.         /* generate output characters in reverse order */
  681.         while (code >= first_ent)
  682.         {
  683.             *(Stack + --stackp) = *(Suffix_of + code);
  684.             code = *(Prefix_of + code);
  685.         }
  686.  
  687.         finchar = *(Suffix_of + code);
  688.         *(Stack + --stackp) = finchar;
  689.  
  690.  
  691.         /* and put them out in forward order, block copy */
  692.         if ((hsize-stackp+outcnt) < out_size)
  693.         {
  694.             memcpy(outptr,Stack+stackp,hsize-stackp);
  695.             outptr += hsize-stackp;
  696.             outcnt += hsize-stackp;
  697.             stackp = hsize;
  698.         }
  699.  
  700.         /* output byte by byte if we can╒t go by blocks */
  701.         else while (stackp < hsize)
  702.                         OUTB(*(Stack + stackp++));
  703.  
  704.  
  705.         /* generate new entry */
  706.         code = free_ent;
  707.         if (code < maxcodemax)
  708.         {
  709.             *(Prefix_of + code) = oldcode;
  710.             *(Suffix_of + code) = finchar;
  711.  
  712.             do
  713.                 code++;
  714.             while ((code < maxcodemax) && (*(Prefix_of + code) != -1));
  715.  
  716.             free_ent = code;
  717.         }
  718.  
  719.         /* remember previous code */
  720.         oldcode = incode;
  721.     }
  722.  
  723. }
  724.  
  725. /* ------------------------------------------------------------------------- */
  726. void get_string(len,s)
  727. int len;
  728. char *s;
  729. {
  730.     read(zipfd, s, len);
  731.     s[len] = 0;
  732. }
  733.  
  734. /* ------------------------------------------------------------------------- */
  735. memcpy(to,from,count)
  736. register char *to,*from;
  737. register unsigned int count;
  738. {
  739.     for(;count>0;--count,++to,++from)
  740.         *to=*from;
  741. }
  742.  
  743. /* -------------------------------------------------------------------------- */
  744. /* -------------------------------------------------------------------------- */
  745. /*
  746.  *  Exploding code derived from Turbo Pascal v. 5.0 source ⌐ R.P. Byrne
  747.  *  (version 2.0 ╤ July 31, 1989)
  748.  *
  749.  */
  750.  
  751. /* -------------------------------------------------------------------------- */
  752. Bad_SF_Tree()
  753. {
  754.     CloseProgressWind();
  755.     DisplayString("\p --  bad Shannon-Fano decode tree  --  file skipped\015");    
  756. }
  757.  
  758. /* -------------------------------------------------------------------------- */
  759. Boolean Add_SF_SubTree(SF_TreePtr,SF_NextFreePtr,CurrNode,LastLeaf,SF_Code,SF_Len,SF_Val)
  760. SF_Node        (*SF_TreePtr)[];
  761. int            *SF_NextFreePtr;
  762. int            CurrNode;
  763. int            LastLeaf;
  764. int            SF_Code;
  765. int            SF_Len;
  766. int            SF_Val;
  767. {
  768.     int        i;
  769.     
  770.     for (i=(SF_Len - 1); i>=1; i--)
  771.     {
  772.         if (CurrNode <= LastLeaf)
  773.         {
  774.             Bad_SF_Tree();
  775.             return(true);
  776.         }
  777.         
  778.         if ((SF_Code >> i) & 0x0001)
  779.         {
  780.             if (-1 == (*SF_TreePtr)[CurrNode].RChild)
  781.             {
  782.                 (*SF_TreePtr)[CurrNode].RChild = *SF_NextFreePtr;
  783.                 (*SF_NextFreePtr)--;
  784.             }
  785.             CurrNode    =    (*SF_TreePtr)[CurrNode].RChild;
  786.         }
  787.         
  788.         else
  789.         {
  790.             if (-1 == (*SF_TreePtr)[CurrNode].LChild)
  791.             {
  792.                 (*SF_TreePtr)[CurrNode].LChild = *SF_NextFreePtr;
  793.                 (*SF_NextFreePtr)--;
  794.             }
  795.             CurrNode    =    (*SF_TreePtr)[CurrNode].LChild;
  796.         }
  797.     }
  798.     
  799.     if (SF_Code & 0x0001)
  800.     {
  801.         if (-1 != (*SF_TreePtr)[CurrNode].RChild)
  802.         {
  803.             Bad_SF_Tree();
  804.             return(true);
  805.         }
  806.         
  807.         else    (*SF_TreePtr)[CurrNode].RChild = SF_Val;
  808.     }
  809.     
  810.     else
  811.     {
  812.         if (-1 != (*SF_TreePtr)[CurrNode].LChild)
  813.         {
  814.             Bad_SF_Tree();
  815.             return(true);
  816.         }
  817.         
  818.         else    (*SF_TreePtr)[CurrNode].LChild = SF_Val;
  819.     }
  820.     
  821.     return (false);        
  822. }
  823.  
  824. /* -------------------------------------------------------------------------- */
  825. Boolean Construct_SF_Tree(SF_TreePtr,SF_NextFreePtr,treesize,LastLeaf)
  826. SF_Node        (*SF_TreePtr)[];
  827. int            *SF_NextFreePtr;
  828. int            treesize;
  829. int            LastLeaf;
  830. {
  831.     SF_BuildRec        SF_Build[256];
  832.     SF_BuildRec        tempnode;
  833.     
  834.     int        OneByte;
  835.     char    CodeLen;
  836.     char    CodeCount;
  837.     
  838.     int        SF_Table_Codes;
  839.     int        SF_Build_Idx;
  840.     int        BuildCount;
  841.     
  842.     unsigned int        Code;
  843.     unsigned int        CodeIncrement;
  844.     int                    LastBitLength;
  845.     
  846.     int        i,j;
  847.  
  848.     Boolean    swapflag=true;
  849.     
  850.     SF_Build_Idx    =    0;
  851.     BuildCount        =    0;
  852.     if(0 == ReadByte(&SF_Table_Codes))
  853.         {
  854.             DisplayString("\p -- unexpected end of file  --  file skipped");
  855.             return(true);
  856.         }
  857.         
  858.     for (i=0; i<=SF_Table_Codes; i++)
  859.     {
  860.         if(0 == ReadByte(&OneByte))
  861.         {
  862.             DisplayString("\p -- unexpected end of file  --  file skipped");
  863.             return(true);
  864.         }
  865.         CodeLen        =    (OneByte & 0x000F) + 1;
  866.         CodeCount    =    (OneByte >> 4) & 0x000F;
  867.         
  868.         for (j=0; j<=CodeCount; j++)
  869.         {
  870.             SF_Build[SF_Build_Idx].Len    =    CodeLen;
  871.             SF_Build[SF_Build_Idx].Val    =    SF_Build_Idx;
  872.             SF_Build_Idx++;
  873.         }
  874.     }
  875.     BuildCount    =    SF_Build_Idx - 1;
  876.     
  877.     /* bubble sort of tree leaves */
  878.     while(swapflag)
  879.     {
  880.         swapflag        =    false;
  881.         for (i=0; i<BuildCount; i++)
  882.         {
  883.             if(     (SF_Build[i].Len > SF_Build[i+1].Len) || 
  884.                  (  (SF_Build[i].Len == SF_Build[i+1].Len) &&
  885.                     (SF_Build[i].Val > SF_Build[i+1].Val)  )     )
  886.             {
  887.                 tempnode.Len        =    SF_Build[i].Len;
  888.                 tempnode.Val        =    SF_Build[i].Val;
  889.                 
  890.                 SF_Build[i].Len        =    SF_Build[i+1].Len;
  891.                 SF_Build[i].Val        =    SF_Build[i+1].Val;
  892.                 
  893.                 SF_Build[i+1].Len    =    tempnode.Len;
  894.                 SF_Build[i+1].Val    =    tempnode.Val;
  895.  
  896.                 swapflag    = true;
  897.             }
  898.         }
  899.     }
  900.     
  901.     Code            =    0;
  902.     CodeIncrement    =    0;
  903.     LastBitLength    =    0;
  904.     
  905.     for (i=BuildCount; i>=0; i--)
  906.     {
  907.         Code    =    Code    +    CodeIncrement;
  908.         
  909.         if(SF_Build[i].Len != LastBitLength)
  910.         {
  911.             LastBitLength    =    SF_Build[i].Len;
  912.             CodeIncrement    =    1 << (16 - LastBitLength);
  913.         }
  914.         SF_Build[i].Code    =    Code >> (16 - SF_Build[i].Len);
  915.         
  916. /*        sprintf(tstring,"\r%3d  %3d  %3d  %4X",i,SF_Build[i].Len,SF_Build[i].Val,SF_Build[i].Code);
  917.         DisplayString(CtoPstr(tstring));    */
  918.         
  919.         if(Add_SF_SubTree(    SF_TreePtr,
  920.                             SF_NextFreePtr,
  921.                             treesize,
  922.                             LastLeaf,
  923.                             SF_Build[i].Code,
  924.                             SF_Build[i].Len,
  925.                             SF_Build[i].Val    )) return (true);
  926.     }
  927. /*    for (i=0;i<=treesize;i++)
  928.         fprintf(sftrees,"\r%3d  %3d  %3d",i,(*SF_TreePtr)[i].LChild,(*SF_TreePtr)[i].RChild);
  929.     fprintf(sftrees,"\r\r"); */
  930.     
  931.     return (false);
  932. }
  933.  
  934. /* -------------------------------------------------------------------------- */
  935. Boolean Init_Explode()
  936. {
  937.     int        i;
  938.     
  939.     DictSize    =    (((lrec.general_purpose_bit_flag >> 1) & 0x01) * 4096) + 4096;
  940.     NumOfTrees    =     ((lrec.general_purpose_bit_flag >> 2) & 0x01) + 2;
  941.     MinMatchLen    =    NumOfTrees;
  942.     
  943.     for (i=0; i<=LENGTH_TREE_ROOT; i++)
  944.     {
  945.         SF_Length[i].LChild        =    -1;
  946.         SF_Length[i].RChild        =    -1;
  947.     }
  948.     NextFreeLength    =    LENGTH_TREE_ROOT - 1;
  949.     
  950.     for (i=0; i<=DISTANCE_TREE_ROOT; i++)
  951.     {
  952.         SF_Distance[i].LChild    =    -1;
  953.         SF_Distance[i].RChild    =    -1;
  954.     }
  955.     NextFreeDistance    =    DISTANCE_TREE_ROOT - 1;
  956.     
  957.     if(3==NumOfTrees) 
  958.     {
  959.         for (i=0; i<=LITERAL_TREE_ROOT; i++)
  960.         {
  961.             SF_Literal[i].LChild =    -1;
  962.             SF_Literal[i].RChild =    -1;
  963.         }
  964.         NextFreeLiteral    =    LITERAL_TREE_ROOT - 1;
  965.         if(Construct_SF_Tree(&SF_Literal,&NextFreeLiteral,LITERAL_TREE_ROOT,LIT_LAST_LEAF)) return(true);
  966.     }
  967.  
  968.     if(Construct_SF_Tree(&SF_Length,&NextFreeLength,LENGTH_TREE_ROOT,LEN_LAST_LEAF)) return(true);
  969.     if(Construct_SF_Tree(&SF_Distance,&NextFreeDistance,DISTANCE_TREE_ROOT,DIST_LAST_LEAF)) return(true);
  970.     
  971.     return (false);
  972. }
  973.  
  974. /* -------------------------------------------------------------------------- */
  975. Boolean Decode_SF_Data(SF_TreePtr,CurrNode,LastLeaf,OutputPtr)
  976. SF_Node        (*SF_TreePtr)[];
  977. int            CurrNode;
  978. int            LastLeaf;
  979. int            *OutputPtr;
  980. {
  981.     int        OneBit;
  982.  
  983.     while (CurrNode > LastLeaf)
  984.     {
  985.         READBIT(1,OneBit);
  986.         
  987.         if (OneBit)
  988.         {
  989.             if (-1 == (*SF_TreePtr)[CurrNode].RChild)
  990.             {
  991.                 Bad_SF_Tree();
  992.                 return(true);
  993.             }            
  994.             
  995.             else    CurrNode = (*SF_TreePtr)[CurrNode].RChild;
  996.         }
  997.         
  998.         else
  999.         {
  1000.             if (-1 == (*SF_TreePtr)[CurrNode].LChild)
  1001.             {
  1002.                 Bad_SF_Tree();
  1003.                 return(true);
  1004.             }            
  1005.             
  1006.             else    CurrNode = (*SF_TreePtr)[CurrNode].LChild;
  1007.         }
  1008.     }
  1009.     *OutputPtr    =    CurrNode;    
  1010.     return (false);
  1011. }            
  1012.  
  1013. /* -------------------------------------------------------------------------- */
  1014.  Explode()
  1015.  {
  1016.     extern byte *Stack;
  1017.     
  1018.     int            State;
  1019.     int            StackIdx;
  1020.     int            StackStart;
  1021.     int            Length;
  1022.     int            DistVal;
  1023.     int            Distance;
  1024.     int            Literal;
  1025.     int            OneByte;
  1026.     int            i;
  1027.  
  1028.     Boolean        BigDictflag;
  1029.     Boolean        LiteralTreeflag;
  1030.  
  1031.     if(Init_Explode()) return;
  1032.     
  1033.     State        =    0;
  1034.     StackIdx    =    0;
  1035.     for (i=0; i<=hsize+1; i++) Stack[i] = 0;
  1036.     
  1037.     BigDictflag        =    (8192 == DictSize);
  1038.     LiteralTreeflag    =    (3 == NumOfTrees);
  1039.     
  1040.     while ((!zipeof) && ((outpos + outcnt) < lrec.uncompressed_size))
  1041.     {
  1042.         READBIT(1,OneByte);
  1043.         if (OneByte)
  1044.         {
  1045.             if(LiteralTreeflag)
  1046.             { 
  1047.                 if(Decode_SF_Data(&SF_Literal,LITERAL_TREE_ROOT,LIT_LAST_LEAF,&Literal)) return;
  1048.             }
  1049.             else    READBIT(8,Literal);
  1050.             
  1051.             OUTB(Literal);
  1052.             Stack[StackIdx]    =    (char) Literal;
  1053.             if(DictSize == ++StackIdx) StackIdx = 0;
  1054.         }
  1055.         
  1056.         else
  1057.         {
  1058.             if (BigDictflag)
  1059.             {
  1060.                 READBIT(7,Distance);
  1061.                 if(Decode_SF_Data(&SF_Distance,DISTANCE_TREE_ROOT,DIST_LAST_LEAF,&DistVal)) return;
  1062.                 Distance    =    (Distance | (DistVal << 7)) & 0x1FFF;
  1063.             }
  1064.             
  1065.             else
  1066.             {
  1067.                 READBIT(6,Distance);
  1068.                 if(Decode_SF_Data(&SF_Distance,DISTANCE_TREE_ROOT,DIST_LAST_LEAF,&DistVal)) return;
  1069.                 Distance    =    (Distance | (DistVal << 6)) & 0x0FFF;
  1070.             }
  1071.             
  1072.             if(Decode_SF_Data(&SF_Length,LENGTH_TREE_ROOT,LEN_LAST_LEAF,&Length)) return;
  1073.             
  1074.             if (63 == Length)
  1075.             {
  1076.                 READBIT(8,i);
  1077.                 Length    =    Length + i;
  1078.             }
  1079.             
  1080.             Length        =    Length + MinMatchLen;
  1081.             StackStart    =    StackIdx - (Distance + 1);
  1082.             if(0 > StackStart) StackStart = StackStart + DictSize;
  1083.             
  1084.             while (Length-- > 0)
  1085.             {
  1086.                 OUTB(Stack[StackStart]);
  1087.                 Stack[StackIdx]    =    Stack[StackStart];
  1088.                 if(DictSize == ++StackIdx)        StackIdx = 0;
  1089.                 if(DictSize == ++StackStart)    StackStart = 0;
  1090.             }
  1091.         }
  1092.     }    
  1093. }
  1094.  
  1095. /* -------------------------------------------------------------------------- */
  1096. /* -------------------------------------------------------------------------- */ 
  1097. OSErr freeSpaceOnVol(vRef,pfreeBytes)
  1098. int     vRef;
  1099. long    *pfreeBytes;
  1100. {
  1101.     HVolumeParam    HPB;
  1102.     OSErr            err;
  1103.     
  1104.     HPB.ioNamePtr    =    0L;
  1105.     HPB.ioVRefNum    =    vRef;
  1106.     HPB.ioVolIndex    =    0;
  1107.     err                =    PBHGetVInfo(&HPB,false);
  1108.     if(err==noErr) *pfreeBytes = (long) HPB.ioVFrBlk * HPB.ioVAlBlkSiz;
  1109.     else           *pfreeBytes = 0L;
  1110.     return(err);
  1111. }
  1112.  
  1113. /* ------------------------------------------------------------------------- */
  1114. Monitor(s1,v1,s2,v2,s3,v3)
  1115. /* debugging routine to monitor variables    */
  1116. char    s1[32],s2[32],s3[32];
  1117. int        v1,v2;
  1118. long    v3;
  1119. {
  1120.     char    ts1[60],ts2[60],ts3[60];
  1121.     sprintf(ts1,"%10d  %s",v1,s1);
  1122.     sprintf(ts2,"%10d  %s",v2,s2);
  1123.     sprintf(ts3,"%10ld  %s",v3,s3);
  1124.     ParamText(CtoPstr(ts1),CtoPstr(ts2),CtoPstr(ts3),"\p");
  1125.     Alert(103,nil);
  1126. }
  1127.  
  1128. /* -------------------------------------------------------------------------- */
  1129. InitProgressWind(dearchivingtype)
  1130. char    *dearchivingtype;
  1131. {
  1132.     int    width;
  1133.     
  1134.     wprogress    =    GetNewWindow(102,&wprogressRec,-1L);
  1135.     SetPort(wprogress);
  1136.     sprintf(tstring,"%s : %s  %ld \304> %ld bytes",
  1137.             dearchivingtype,
  1138.             filename,
  1139.             lrec.compressed_size,
  1140.             lrec.uncompressed_size);
  1141.     TextFont(150);
  1142.     TextSize(9);
  1143.     TextFace(bold);
  1144.     width    =    StringWidth(CtoPstr(tstring));
  1145.     MoveTo(((416-width)/2),15);
  1146.     DrawString(tstring);
  1147.     SetRect(&prect,38,22,380,40);
  1148.     FrameRect(&prect);
  1149.     
  1150.     numblocks        =    20;
  1151.     sizeblock        =    lrec.compressed_size/20L;
  1152.     if(50000L > lrec.compressed_size) 
  1153.     {
  1154.         sizeblock    =     lrec.compressed_size/10L;
  1155.         numblocks    =    10;
  1156.     }
  1157.     if(10000L > lrec.compressed_size) 
  1158.     {
  1159.         sizeblock    =     lrec.compressed_size/4L;
  1160.         numblocks    =    4;
  1161.     }
  1162.     if( 2000L > lrec.compressed_size)
  1163.     {
  1164.         sizeblock    =    lrec.compressed_size/2L;
  1165.         numblocks    =    2;
  1166.     }
  1167.     progresscount    =    0L;
  1168.     blockcount        =    0;
  1169.     PenPat(gray);
  1170. }
  1171.  
  1172. /* -------------------------------------------------------------------------- */
  1173. UpdateProgressWind(numblocks,blockcount)
  1174. int    numblocks,blockcount;
  1175. {
  1176.     Rect    r;
  1177. /*    if(blockcount > numblocks) blockcount = numblocks;    */
  1178.     SetRect(&r,(39+(blockcount-1)*340/numblocks),23,(39+blockcount*340/numblocks),39);
  1179.     PaintRect(&r);
  1180. }
  1181.  
  1182. /* -------------------------------------------------------------------------- */
  1183. CloseProgressWind()
  1184. {
  1185.     CloseWindow(wprogress);
  1186. }
  1187.  
  1188. /* -------------------------------------------------------------------------- */
  1189. void set_file_time() 
  1190. {
  1191.     HFileInfo        FiInfo;
  1192.     unsigned char    tfname[256];
  1193.     OSErr            result;
  1194.     DateTimeRec        dtr;
  1195.     long            seconds;
  1196.     
  1197.     strcpy(tstring,filename);
  1198.     CtoPstr(tstring);
  1199.     strcpy(tfname,tstring);
  1200.     FiInfo.ioNamePtr    =    tfname;
  1201.     FiInfo.ioVRefNum    =    0;
  1202.     FiInfo.ioFVersNum    =    0;
  1203.     FiInfo.ioFDirIndex    =    0;
  1204.     
  1205.     result    =    PBGetFInfo(&FiInfo,false);
  1206.     
  1207.     dtr.day        =      lrec.last_mod_file_date & 0x1F;
  1208.     dtr.month    =     (lrec.last_mod_file_date >> 5) & 0x0F;
  1209.     dtr.year    =    ((lrec.last_mod_file_date >> 9) & 0x7F) + 1980;
  1210.     
  1211.     dtr.second    =    0;
  1212.     dtr.minute    =    (lrec.last_mod_file_time >> 5) & 0x3F;
  1213.     dtr.hour    =    (lrec.last_mod_file_time >>11) & 0x1F;
  1214.     dtr.second    = 2*(lrec.last_mod_file_time & 0x1F);
  1215.     
  1216.     Date2Secs(&dtr,&seconds);
  1217.     FiInfo.ioFlCrDat    =    seconds;
  1218.     FiInfo.ioFlMdDat    =    seconds;
  1219.     result    =    PBSetFInfo(&FiInfo,false);    
  1220. }
  1221.  
  1222. /* -------------------------------------------------------------------------- */
  1223. int create_output_file()
  1224. /* return non-0 if creat failed */
  1225. {
  1226.     extern    local_file_header lrec;
  1227.     char    temp[256];
  1228.     long    freebytes;
  1229.     int        filerr;
  1230.     
  1231.     freeSpaceOnVol(SFzipfd.vRefNum,&freebytes);
  1232.     if(lrec.uncompressed_size > freebytes)
  1233.     {
  1234.         sprintf(tstring,"***********: %-12s  --  no space on volume  --  file skipped",filename);
  1235.         DisplayString(CtoPstr(tstring));
  1236.         return(1);
  1237.     }
  1238.     
  1239.     outfd = creat(filename, O_CREAT | O_RDWR | O_BINARY);
  1240.  
  1241.     if (outfd == EOF) 
  1242.     {
  1243.         sprintf(tstring,"***********: %-12s  --  can╒t create output file  --  file skipped",filename);
  1244.         DisplayString(CtoPstr(tstring));
  1245.         return(1);
  1246.     }
  1247.         
  1248.     strcpy(tstring,filename);
  1249.     GetFInfo(CtoPstr(tstring),NULL,&ffinfo);
  1250.     ffinfo.fdCreator    =    'pZIP';
  1251.     ffinfo.fdType        =    'TEXT';
  1252.     if((0L<zipoffset[dindex]) && (4!=stcpm(filename,".GIF",temp)) && (4!=stcpm(filename,".gif",temp))) ffinfo.fdType='pBIN';
  1253.     SetFInfo(tstring,NULL,&ffinfo);
  1254.     
  1255. /*  write a single byte at EOF to pre-allocate the file */ 
  1256.     lseek(outfd, lrec.uncompressed_size-1L, SEEK_SET);
  1257.     
  1258.     filerr    =    write(outfd, "?", 1);
  1259.     
  1260.     lseek(outfd, 0L, SEEK_SET);
  1261.     return(0);
  1262. }
  1263.  
  1264. /* ------------------------------------------------------------------------- */
  1265. extract_member()
  1266. {
  1267.     extern    local_file_header lrec;
  1268.     
  1269.     gifinfo         gi;
  1270.     char        colors,temp[256];
  1271.     int            ncolors;
  1272.     long        freebytes;
  1273.     
  1274.     unsigned b;
  1275.     FILE    *in,*out;
  1276.     int        ch;
  1277.  
  1278.     bits_left    =    0;
  1279.     bitbuf        =    0;
  1280.     incnt        =    0;
  1281.     outpos        =    0L;
  1282.     outcnt        =    0;
  1283.     outptr        =    outbuf;
  1284.     zipeof        =    0;
  1285.     crc32val    =    0xFFFFFFFFL;
  1286.     
  1287.     /* create the output file with READ and WRITE permissions */
  1288.     
  1289.     if(7>lrec.compression_method)
  1290.     {
  1291.         if (create_output_file())
  1292.         {
  1293.             DisplayLn();
  1294.             SysBeep(1);
  1295.             return(1);
  1296.         } 
  1297.     }
  1298.  
  1299.     switch (lrec.compression_method) 
  1300.     {
  1301.  
  1302.     case 0:        /* stored */
  1303.         {
  1304.             sprintf(tstring," Extracting: %-12s ", filename);
  1305.             DisplayString(CtoPstr(tstring));
  1306.             
  1307.             InitProgressWind("Extracting");
  1308.             while (ReadByte(&b)) OUTB(b);
  1309.             CloseProgressWind();
  1310.         }
  1311.         break;
  1312.  
  1313.     case 1: 
  1314.         {
  1315.             sprintf(tstring,"UnShrinking: %-12s ", filename);
  1316.             DisplayString(CtoPstr(tstring));
  1317.  
  1318.             InitProgressWind("UnShrinking");
  1319.             unShrink();
  1320.             CloseProgressWind();
  1321.         }
  1322.         break;
  1323.  
  1324.     case 2:
  1325.     case 3:
  1326.     case 4:
  1327.     case 5:
  1328.         {
  1329.             sprintf(tstring,"  Expanding: %-12s ",filename);
  1330.             DisplayString(CtoPstr(tstring));
  1331.  
  1332.             InitProgressWind("Expanding");
  1333.             unReduce();
  1334.             CloseProgressWind();
  1335.         }
  1336.         break;
  1337.         
  1338.     case 6:
  1339.         {
  1340.             sprintf(tstring,"  Exploding: %-12s ",filename);
  1341.             DisplayString(CtoPstr(tstring));
  1342.             InitProgressWind("Exploding");
  1343.             Explode();
  1344.             CloseProgressWind();
  1345.         }
  1346.         break;
  1347.         
  1348.     default:
  1349.         {
  1350.             sprintf(tstring,"           : %-12s  --  unknown compression method  --  file skipped\015",filename);
  1351.             DisplayString(CtoPstr(tstring));
  1352.         }
  1353.     }
  1354.     
  1355.     if(6<lrec.compression_method) return;
  1356.     
  1357.     /* write the last partial buffer, if any */
  1358.     if (outcnt > 0)
  1359.     {
  1360.         UpdateCRC(outbuf, outcnt);
  1361.         write(outfd, outbuf, outcnt);
  1362.     }
  1363.  
  1364.     crc32val = -1 - crc32val;
  1365.  
  1366.     if (crc32val != lrec.crc32)
  1367.     {
  1368.         sprintf(tstring," --  Bad CRC %08lX  (should be %08lX)", lrec.crc32, crc32val);
  1369.         DisplayString(CtoPstr(tstring));
  1370.     }
  1371.     else     DisplayString("\p --  successful");
  1372.  
  1373.     /* if file ended in '.GIF' or '.gif' display additional GIF file info */
  1374.     if((4==stcpm(filename,".GIF",temp)) || (4==stcpm(filename,".gif",temp)))
  1375.     {
  1376.         lseek(outfd,0L,0L);
  1377.         read(outfd,&gi,sizeof(gifinfo));
  1378.         swap_bytes(&gi.screen_width);
  1379.         swap_bytes(&gi.screen_height);
  1380.         colors    =    gi.color_resolution & '\007';
  1381.         ncolors    =    1 << (1+(int) colors);
  1382.         sprintf(tstring,"\015                           --  GIF file:  %dx%d  %d colors",gi.screen_width,gi.screen_height,ncolors);
  1383.         DisplayString(CtoPstr(tstring));        
  1384.     }
  1385.     
  1386.     close(outfd);
  1387.  
  1388.     /* strip linefeeds from text files if stripLFflag = true */
  1389.     if (stripLFflag && (0>zipoffset[dindex]))
  1390.     {
  1391.         freeSpaceOnVol(SFzipfd.vRefNum,&freebytes);
  1392.         if(lrec.uncompressed_size > freebytes)
  1393.         {
  1394.             DisplayString("\p\015                           --  no space on volume for LF stripped file");
  1395.         }
  1396.         else
  1397.         {
  1398.             DisplayString("\p\015                           --  stripping LF's ");
  1399.             in    =    fopen(filename,"rb");
  1400.             out    =    fopen("pZIPtemp01","wb");
  1401.  
  1402.             if (out != NULL)
  1403.             {
  1404.                 strcpy(tstring,"pZIPtemp01");
  1405.                 GetFInfo(CtoPstr(tstring),NULL,&ffinfo);
  1406.                 ffinfo.fdCreator    =    'pZIP';
  1407.                 ffinfo.fdType        =    'TEXT';
  1408.                 SetFInfo(tstring,NULL,&ffinfo);
  1409.             
  1410.                 while ((ch=getc(in)) != EOF)  if('\012' != ch) putc(ch,out);
  1411.  
  1412.                 fclose(in);
  1413.                 fclose(out);
  1414.                 remove(filename);
  1415.                 rename("pZIPtemp01",filename);
  1416.                 DisplayString("\p --  successful");
  1417.             }
  1418.             else
  1419.             {    
  1420.                 DisplayString("\p\015                       --  error opening LF stripped file  --  skipped");    
  1421.             }
  1422.  
  1423.         }
  1424.     }
  1425.         
  1426.     /* set output file date and time */
  1427.     set_file_time();
  1428.     DisplayLn();
  1429. }
  1430.  
  1431. /* ------------------------------------------------------------------------- */
  1432. void process_local_file_header()
  1433. {
  1434.     extern local_file_header lrec;
  1435.     char temp[256];
  1436.     
  1437.     read(zipfd, &lrec, sizeof(lrec));
  1438.  
  1439.     swap_bytes(&lrec.filename_length);
  1440.     swap_bytes(&lrec.extra_field_length);
  1441.     swap_lbytes(&lrec.compressed_size);
  1442.     swap_lbytes(&lrec.uncompressed_size);
  1443.     swap_bytes(&lrec.last_mod_file_time);
  1444.     swap_bytes(&lrec.last_mod_file_date);
  1445.     swap_bytes(&lrec.compression_method);
  1446.     swap_bytes(&lrec.general_purpose_bit_flag);
  1447.     swap_lbytes(&lrec.crc32);
  1448.     
  1449.     get_string(lrec.filename_length, filename);
  1450.     get_string(lrec.extra_field_length, extra);
  1451.     
  1452.     if(TEXTfilterflag && (0L<zipoffset[dindex]) && (4!=stcpm(filename,".GIF",temp)) && (4!=stcpm(filename,".gif",temp))) return;
  1453.     
  1454.     if (choosefileflag)
  1455.     {
  1456.         strcpy(tstring,"Dearchive ╥");
  1457.         strcat(tstring,filename);
  1458.         strcat(tstring,"╙?");
  1459.         ParamText(CtoPstr(tstring),"\p","\p","\p");
  1460.         InitCursor();
  1461.         if(1==Alert (102,nil)) 
  1462.         {
  1463.             c    =    GetCursor(watchCursor);
  1464.             SetCursor(*c);
  1465.             extract_member();
  1466.         }
  1467.     }
  1468.     else extract_member();
  1469. }
  1470.  
  1471. /* -------------------------------------------------------------------------- */
  1472. long process_central_file_header()
  1473. {
  1474.     central_directory_file_header rec;
  1475.     char filename[STRSIZ];
  1476.     char extra[STRSIZ];
  1477.     char comment[STRSIZ];
  1478.     static char *method[8]={"     Stored","     Shrunk","   Reduced1","   Reduced2","   Reduced3","   Reduced4","   Imploded","    Unknown"};
  1479.     static char *ny[2]={" no","yes"};
  1480.     static char *mo[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
  1481.     long    offset;
  1482.     int        day,month,year,hour,minute,second;
  1483.     
  1484.     read(zipfd, &rec, sizeof(rec));
  1485.  
  1486.     swap_bytes(&rec.compression_method);
  1487.     swap_lbytes(&rec.compressed_size);
  1488.     swap_lbytes(&rec.uncompressed_size);
  1489.     swap_bytes(&rec.last_mod_file_time);
  1490.     swap_bytes(&rec.last_mod_file_date);
  1491.     swap_lbytes(&rec.crc32);
  1492.     swap_bytes(&rec.internal_file_attributes);
  1493.     swap_bytes(&rec.filename_length);
  1494.     swap_bytes(&rec.extra_field_length);
  1495.     swap_bytes(&rec.file_comment_length);
  1496.     swap_lbytes(&rec.relative_offset_local_header);
  1497.  
  1498.     get_string(rec.filename_length,filename);
  1499.     get_string(rec.extra_field_length,extra);
  1500.     get_string(rec.file_comment_length,comment);
  1501.     
  1502.     if(6<rec.compression_method) rec.compression_method = 7;
  1503.     
  1504.     day        =      rec.last_mod_file_date & 0x1F;    
  1505.     month    =     (rec.last_mod_file_date >> 5) & 0x0F;
  1506.     year    =    ((rec.last_mod_file_date >> 9) & 0x7F) + 80;
  1507.     
  1508.     hour    =     (rec.last_mod_file_time >>11) & 0x1F;
  1509.     minute    =     (rec.last_mod_file_time >> 5) & 0x3F;
  1510.     second    =  2*(rec.last_mod_file_time & 0x1F);
  1511.  
  1512.     sprintf(tstring,"%-12s%s%10ld %10ld%4d-%3s-%2d  %02d:%02d:%02d  %08lX  %3s\015",
  1513.             filename,
  1514.             method[rec.compression_method],
  1515.             rec.compressed_size,
  1516.             rec.uncompressed_size,
  1517.             day,
  1518.             mo[month-1],
  1519.             year,
  1520.             hour,
  1521.             minute,
  1522.             second,
  1523.             rec.crc32,
  1524.             ny[rec.internal_file_attributes]);
  1525.             
  1526.     DisplayString(CtoPstr(tstring));
  1527.     offset    =    1L + rec.relative_offset_local_header;
  1528.     if (1==rec.internal_file_attributes) offset = -offset;
  1529.     return(offset);
  1530. }
  1531.  
  1532. /* ------------------------------------------------------------------------- */
  1533. int process_end_central_dir()
  1534. {
  1535.     end_central_dir_record rec;
  1536.     char comment[2048];
  1537.     Rect    drect;
  1538.  
  1539.     lseek(zipfd,5L,1);
  1540.     read(zipfd, &rec, sizeof(rec));
  1541.     swap_bytes(&rec.total_entries_central_dir);
  1542.     swap_lbytes(&rec.offset_start_central_directory);
  1543.     swap_bytes(&rec.zipfile_comment_length);
  1544.     get_string(rec.zipfile_comment_length,comment);
  1545.         
  1546.     wlistflag    =    true;
  1547.     wlist    =    GetNewDWindow(101,-1L);
  1548.     SetWTitle(wlist,&SFzipfd.fName);
  1549.     SetDWindowStyle(wlist,150,9,1,0);
  1550. /*    rec.zipfile_comment_length = stripLFfn(rec.zipfile_comment_length,comment);    */
  1551.     DisplayText(comment,(long) rec.zipfile_comment_length);
  1552.     lseek(zipfd,rec.offset_start_central_directory,0);
  1553.     return(rec.total_entries_central_dir);
  1554. }
  1555.  
  1556. /* ------------------------------------------------------------------------- */
  1557. long labs(x)
  1558. long x;
  1559. {
  1560.     long y;
  1561.     y    =    x;
  1562.     if(0L>y)    y    =    -y;
  1563.     return(y);
  1564. }
  1565.  
  1566. /* ------------------------------------------------------------------------- */
  1567. void process_headers()
  1568. {
  1569.     longint sig;
  1570.     
  1571.     if(!wlistflag)
  1572.     {
  1573.         SysBeep(1);
  1574.         strcpy(tstring,"\015Cannot extract until ZIP file opened!");
  1575.         ParamText(CtoPstr(tstring),"\p","\p","\p");
  1576.         HiliteMenu(nil);
  1577.         (void) StopAlert(101,nil);
  1578.         return;
  1579.     }    
  1580.     
  1581.     if(finishedflag) 
  1582.     {
  1583.         SysBeep(1);
  1584.         strcpy(tstring,"\015ZIP file extraction completed for this file!");
  1585.         ParamText(CtoPstr(tstring),"\p","\p","\p");
  1586.         HiliteMenu(nil);
  1587.         (void) StopAlert(101,nil);
  1588.         return;
  1589.     }
  1590.     c    =    GetCursor(watchCursor);
  1591.     SetCursor(*c);
  1592.     
  1593.     for (dindex=0;dindex<direntries;dindex++)
  1594.         {
  1595.             lseek(zipfd,labs(zipoffset[dindex])-1,0);
  1596.             
  1597.             read(zipfd, &sig, sizeof(sig));
  1598.             
  1599.             if (sig != LOCAL_FILE_HEADER_SIGNATURE)
  1600.                 {
  1601.                     DisplayString("\pBad ZIP file local header signature--file skipped\015");
  1602.                 }
  1603.                 
  1604.                 
  1605.             else process_local_file_header();
  1606.         }
  1607.     InitCursor();
  1608.     close(zipfd);
  1609.     finishedflag    =    true;
  1610.     Delay(20L,sig);
  1611.     SysBeep(1);
  1612.     Delay(5L,sig);
  1613.     SysBeep(1);
  1614.     strcpy(tstring,"\015ZIP file extraction completed!");
  1615.     ParamText(CtoPstr(tstring),"\p","\p","\p");
  1616.     HiliteMenu(nil);
  1617.     (void) NoteAlert (101,nil);
  1618. }
  1619.      
  1620. /* ------------------------------------------------------------------------- */    
  1621. AllocateBuffers()
  1622. {
  1623.     int buffer_fail = 0;
  1624.  
  1625.     extern int *Prefix_of;
  1626.     extern byte *Suffix_of;
  1627.     extern byte *Stack;
  1628.     
  1629.     int i;
  1630.     
  1631.     Prefix_of = calloc(hsize+1,2);
  1632.     Suffix_of = calloc(hsize+1,1);
  1633.     Stack     = calloc(hsize+1,1);
  1634.  
  1635. /* allocate i/o buffers */
  1636.     inbuf         =    (byte *) (mlalloc(INBUFSIZ));
  1637.     outbuf        =    (byte *) (mlalloc(OUTBUFSIZ));
  1638.     in_size        =    INBUFSIZ;
  1639.     out_size    =    OUTBUFSIZ;
  1640.     
  1641.     if ((inbuf == NULL) || (outbuf == NULL)) 
  1642.     {
  1643.         ParamText("\pInsufficient memory to allocate buffers!","\p","\p","\p");
  1644.         (void) StopAlert (101,nil);
  1645.         SkelWhoa();
  1646.     }
  1647. }
  1648.  
  1649. /* ------------------------------------------------------------------------- */
  1650. aboutUnZip()
  1651. {
  1652.     (void) Alert(100,nil);
  1653. }
  1654.  
  1655. /* ------------------------------------------------------------------------- */
  1656. setLFflag()
  1657. {
  1658.     if (!stripLFflag) 
  1659.     {
  1660.         stripLFflag    =    true;
  1661.         CheckItem(mOptions,3,true);
  1662.         mstrip    =    NewMenu(5,"\p*Strip LF on*");
  1663.         SkelMenu(mstrip,nil,nil);
  1664.     }
  1665.     else
  1666.     {
  1667.         stripLFflag    =    false;
  1668.         CheckItem(mOptions,3,false);
  1669.         mstrip    =    NewMenu(5,"\p");
  1670.         SkelMenu(mstrip,nil,nil);
  1671.     }
  1672. }
  1673.  
  1674. /* ------------------------------------------------------------------------- */
  1675. setTEXTfilterflag()
  1676. {
  1677.     if (!TEXTfilterflag) 
  1678.     {
  1679.         TEXTfilterflag    =    true;
  1680.         CheckItem(mOptions,4,true);
  1681.         mfilter    =    NewMenu(4,"\p*.GIF & TEXT filter*");
  1682.         SkelMenu(mfilter,nil,nil);
  1683.     }
  1684.     else
  1685.     {
  1686.         TEXTfilterflag    =    false;
  1687.         CheckItem(mOptions,4,false);
  1688.         mfilter    =    NewMenu(4,"\p");
  1689.         SkelMenu(mfilter,nil,nil);
  1690.     }
  1691. }
  1692.  
  1693. /* ------------------------------------------------------------------------- */
  1694. setchoosefileflag()
  1695. {
  1696.     if (!choosefileflag) 
  1697.     {
  1698.         choosefileflag    =    true;
  1699.         CheckItem(mOptions,5,true);
  1700.     }
  1701.     else
  1702.     {
  1703.         choosefileflag    =    false;
  1704.         CheckItem(mOptions,5,false);
  1705.     }
  1706. }
  1707.  
  1708. /* ------------------------------------------------------------------------- */
  1709. openfile()
  1710. {
  1711.     extern int direntries;
  1712.     long    sig;
  1713.     long    flength;
  1714.     long    temp;
  1715.     
  1716.     if(wlistflag)
  1717.     {
  1718.         if (!finishedflag) close(zipfd);
  1719.         SkelRmveWind(wlist);
  1720.         wlistflag        =    false;
  1721.     }
  1722.     finishedflag    =    false;
  1723.     
  1724.     SFGetFile(bloc,"\p",nil,-1,nil,nil,&SFzipfd);
  1725.     
  1726.     if(!SFzipfd.good) return;
  1727.     else SetVol("\p",SFzipfd.vRefNum);
  1728.     
  1729.     c    =    GetCursor(watchCursor);
  1730.     SetCursor(*c);
  1731.     stccpy(tstring,&SFzipfd.fName,64);
  1732.     zipfd    =    open(PtoCstr(tstring), O_RDONLY | O_BINARY);
  1733.     flength    =    lseek(zipfd,-22L,2);
  1734.     
  1735.     while (1)
  1736.     {
  1737.         read(zipfd,&sig,sizeof(sig));
  1738.         
  1739.         temp    =    lseek(zipfd,-5L,1);
  1740.         
  1741.         if( (45L>=temp) || (1024L<=(flength-temp)) )
  1742.             {
  1743.             /*    not a ZIP file alert    */
  1744.                 stccpy(tstring,&SFzipfd.fName,64);
  1745.                 PtoCstr(tstring);
  1746.                 strcat(tstring,"\015\015Not a ZIP file!");
  1747.                 ParamText(CtoPstr(tstring),"\p","\p","\p");
  1748.                 InitCursor();
  1749.                 SysBeep(1);
  1750.                 HiliteMenu(nil);
  1751.                 (void) StopAlert (101,nil);
  1752.                 close(zipfd);
  1753.                 return;
  1754.             }
  1755.         
  1756.         if (sig == END_CENTRAL_DIR_SIGNATURE) 
  1757.             {
  1758.                 direntries    =    process_end_central_dir();
  1759.                 break;
  1760.             }
  1761.         
  1762.     }
  1763.     
  1764.     DisplayString("\p\015\015File Name        Method  Size Now  Full Size     Date      Time       CRC   Text\015");
  1765.     DisplayString("\p---------      --------  --------  ---------  ---------  --------  -------- ----\015");
  1766.     
  1767.     for (dindex=0;dindex<direntries;dindex++)
  1768.     {
  1769.     
  1770.     read(zipfd, &sig, sizeof(sig)); 
  1771.             
  1772.     if (sig == CENTRAL_FILE_HEADER_SIGNATURE) zipoffset[dindex]=process_central_file_header();
  1773.             
  1774.     }
  1775.     DisplayLn();
  1776.     InitCursor();
  1777.     SysBeep(6);
  1778.     SetDWindowPos(wlist,0);
  1779.     ShowWindow(wlist);
  1780. }
  1781.  
  1782. /* ------------------------------------------------------------------------- */
  1783. DoFileMenu(item)
  1784. int item;
  1785. {
  1786.     switch(item)
  1787.     {
  1788.         case 1:    openfile();    break;
  1789.         case 2:    {
  1790.                     cfree(Prefix_of);
  1791.                     cfree(Suffix_of);
  1792.                     cfree(Stack);
  1793.                     cfree(inbuf);
  1794.                     cfree(outbuf);
  1795.                     SkelWhoa();
  1796.                     break;
  1797.                 }
  1798.     }
  1799. }
  1800.  
  1801. /* ------------------------------------------------------------------------- */
  1802. DoOptionsMenu(item)
  1803. int item;
  1804. {
  1805.     switch(item)
  1806.     {
  1807.         case 1:    process_headers(); break;
  1808.         case 2: break;
  1809.         case 3:    setLFflag(); break;
  1810.         case 4: setTEXTfilterflag();break;
  1811.         case 5: setchoosefileflag(); break;
  1812.     }
  1813. }
  1814.     
  1815. /* ------------------------------------------------------------------------- */
  1816. void main()
  1817. {
  1818.     SkelInit(6,nil);
  1819.     SkelApple("\pAbout UnZip 1.01╔",aboutUnZip);
  1820.  
  1821.     mFile        =    GetMenu(101);
  1822.     (void) SkelMenu(mFile,DoFileMenu,nil,false);
  1823.     mOptions    =    GetMenu(102);
  1824.     (void) SkelMenu(mOptions,DoOptionsMenu,nil,true);
  1825.     
  1826.     AllocateBuffers();
  1827.     SkelMain();
  1828.     SkelClobber();
  1829. }
  1830.